﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using King.Engine.Content;
using Microsoft.Xna.Framework;

namespace King.Engine.GameObjects
{

    /// <summary>
    /// A game object with a single, looping animation
    /// </summary>
    public abstract class SimpleAnimatedObject : GameObject
    {

        #region Fields

        private Animation _animation;
        private bool _isHorizontallyFlipped;
        private bool _isVerticallyFlipped;

        #endregion


        #region Properties

        public bool IsHorizontallyFlipped
        {
            get
            {
                return _isHorizontallyFlipped;
            }
            set
            {
                _isHorizontallyFlipped = value;
                _animation.IsHorizontallyFlipped = value;
            }
        }

        public bool IsVerticallyFlipped
        {
            get
            {
                return _isHorizontallyFlipped;
            }
            set
            {
                _isVerticallyFlipped = value;
                _animation.IsVerticallyFlipped = value;
            }
        }

        protected internal Animation Animation
        {
            get
            {
                return _animation;
            }
            internal set
            {
                _animation = value;
            }
        }
        
        #endregion


        #region Constructor

        /// <summary>
        /// Create an AnimatedObject with the given animation
        /// </summary>
        protected SimpleAnimatedObject(Animation animation)
        {
            _animation = animation;
        }

        /// <summary>
        /// Create an AnimatedObject with a square animation using the given parameters
        /// </summary>
        /// <param name="animationName">Name of the animation</param>
        /// <param name="frameSize">Side length of each frame square</param>
        /// <param name="numFrames">Number of frames in the animation</param>
        /// <param name="frameTime">Duration of each frame</param>
        /// <param name="layerDepth">Draw depth of the animation</param>
        protected SimpleAnimatedObject(string animationName, int frameSize, int numFrames, int frameTime, float layerDepth)
        {
            _animation = new Animation(animationName, frameSize, numFrames, frameTime, layerDepth);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="animationName">Name of the animation</param>
        /// <param name="frameWidth">Width of each frame</param>
        /// <param name="frameHeight">Height of each frame</param>
        /// <param name="numFrames">Number of frames</param>
        /// <param name="frameTime">Duration of each frame</param>
        /// <param name="numColumns">Number of columns in the spritesheet</param>
        /// <param name="layerDepth">Draw depth of the animation</param>
        protected SimpleAnimatedObject(string animationName, int frameWidth, int frameHeight, int numFrames, int frameTime, int numColumns, float layerDepth)
        {
            _animation = new Animation(animationName, frameWidth, frameHeight, numFrames, frameTime, numColumns, layerDepth);
        }

        internal SimpleAnimatedObject()
        {

        }

        #endregion


        #region Public Methods

        /// <summary>
        /// Restart the animation
        /// </summary>
        public virtual void Restart()
        {
            _animation.Restart();
            _animation.IsHorizontallyFlipped = _isHorizontallyFlipped;
            _animation.IsVerticallyFlipped = _isVerticallyFlipped;
        }

        protected override void UpdateAfterComponents(GameTime gameTime)
        {
            _animation.Update(gameTime);
            base.UpdateAfterComponents(gameTime);
        }

        protected override void DrawObject()
        {
            _animation.Draw(this.Bounds);
        }

        #endregion

    }

    /// <summary>
    /// An animated game object that supports multiple animations.
    /// </summary>
    /// <typeparam name="T">Each animation is keyed by a value of type T. This should be an enum</typeparam>
    public abstract class AnimatedGameObject<T> : SimpleAnimatedObject
    {

        #region Fields

        private Dictionary<T, Animation> _animations;

        #endregion
        

        #region Constructor

        /// <summary>
        /// Create an animated game object
        /// </summary>
        /// <param name="animations">Dictionary that maps T values to animations</param>
        /// <param name="initialAnimation">The first animation</param>
        public AnimatedGameObject(Dictionary<T, Animation> animations, T initialAnimation)
        {
            _animations = animations;
            Animation = animations[initialAnimation];
        }

        /// <summary>
        /// Create an animated game object where the first animation is non-looping
        /// </summary>
        /// <param name="animations">Dictionary that maps T values to animations</param>
        /// <param name="initialAnimation">The first animation</param>
        /// <param name="complete">The callback from when the first animation has completed</param>
        public AnimatedGameObject(Dictionary<T, Animation> animations, T initialAnimation, Action complete)
        {
            _animations = animations;
            Animation = animations[initialAnimation];
            Animation.Complete = complete;
        }

        #endregion


        #region Public Methods

        /// <summary>
        /// Set the animation from the given key
        /// </summary>
        public void SetAnimation(T animation)
        {
            this.Animation = _animations[animation];
            this.Animation.IsLoop = false;
            Restart();
        }

        /// <summary>
        /// Set a non-looping animation from the given key.
        /// </summary>
        /// <param name="complete">The callback for when the animation has completed</param>
        public void SetNonLoopingAnimation(T animation, Action complete)
        {
            SetAnimation(animation);
            this.Animation.IsLoop = false;
            this.Animation.Complete = complete;
        }
        
        #endregion

    }

}
